/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2016
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Author: Sébastien Deronne <sebastien.deronne@gmail.com>
 */

#ifndef WIFI_UTILS_H
#define WIFI_UTILS_H

#include "block-ack-type.h"
#include "wifi-preamble.h"
#include "wifi-mode.h"

namespace ns3 {

class WifiNetDevice;
class WifiMacHeader;
class WifiMode;
class Packet;
class Time;

/**
 * Convert from dBm to Watts.
 *
 * \param dbm the power in dBm
 *
 * \return the equivalent Watts for the given dBm
 */
double DbmToW (double dbm);
/**
 * Convert from dB to ratio.
 *
 * \param db
 *
 * \return ratio
 */
double DbToRatio (double db);
/**
 * Convert from Watts to dBm.
 *
 * \param w the power in Watts
 *
 * \return the equivalent dBm for the given Watts
 */
double WToDbm (double w);
/**
 * Convert from ratio to dB.
 *
 * \param ratio
 *
 * \return dB
 */
double RatioToDb (double ratio);
/**
 * \param frequency the frequency to check
 * \return whether frequency is in the 2.4 GHz band
 */
bool Is2_4Ghz (double frequency);
/**
 * \param frequency the frequency to check
 * \return whether frequency is in the 5 GHz band
 */
bool Is5Ghz (double frequency);
/**
 * Convert the guard interval to nanoseconds based on the wifimode.
 *
 * \param mode the wifimode
 * \param device pointer to the WifiNetDevice object
 *
 * \return the guard interval duration in nanoseconds
 */
uint16_t ConvertGuardIntervalToNanoSeconds (WifiMode mode, const Ptr<WifiNetDevice> device);
/**
 * Convert the guard interval to nanoseconds based on the wifimode.
 *
 * \param mode the wifimode
 * \param htShortGuardInterval whether HT/VHT short guard interval is enabled
 * \param heGuardInterval the HE guard interval duration
 *
 * \return the guard interval duration in nanoseconds
 */
uint16_t ConvertGuardIntervalToNanoSeconds (WifiMode mode, bool htShortGuardInterval, Time heGuardInterval);
/**
 * Return the preamble to be used for the transmission.
 *
 * \param modulation the modulation selected for the transmission
 * \param useShortPreamble whether short preamble should be used
 * \param useGreenfield whether HT greenfield should be used
 *
 * \return the preamble to be used for the transmission
 */
WifiPreamble GetPreambleForTransmission (WifiModulationClass modulation, bool useShortPreamble, bool useGreenfield);
/**
 * Return the channel width that corresponds to the selected mode (instead of
 * letting the PHY's default channel width). This is especially useful when using
 * non-HT modes with HT/VHT/HE capable stations (with default width above 20 MHz).
 *
 * \param mode selected WifiMode
 * \param maxSupportedChannelWidth maximum channel width supported by the PHY layer
 * \return channel width adapted to the selected mode
 */
uint16_t GetChannelWidthForTransmission (WifiMode mode, uint16_t maxSupportedChannelWidth);
/**
 * Return whether the modulation class of the selected mode for the
 * control answer frame is allowed.
 *
 * \param modClassReq modulation class of the request frame
 * \param modClassAnswer modulation class of the answer frame
 *
 * \return true if the modulation class of the selected mode for the
 * control answer frame is allowed, false otherwise
 */
bool IsAllowedControlAnswerModulationClass (WifiModulationClass modClassReq, WifiModulationClass modClassAnswer);
/**
 * Return the total ACK size (including FCS trailer).
 *
 * \return the total ACK size
 */
uint32_t GetAckSize (void);
/**
 * Return the total Block ACK size (including FCS trailer).
 *
 * \param type the Block ACK type
 * \return the total Block ACK size
 */
uint32_t GetBlockAckSize (BlockAckType type);
/**
 * Return the total RTS size (including FCS trailer).
 *
 * \return the total RTS size
 */
uint32_t GetRtsSize (void);
/**
 * Return the total CTS size (including FCS trailer).
 *
 * \return the total CTS size
 */
uint32_t GetCtsSize (void);
/**
 * \param seq MPDU sequence number
 * \param winstart sequence number window start
 * \param winsize the size of the sequence number window
 * \returns true if in the window
 *
 * This method checks if the MPDU's sequence number is inside the scoreboard boundaries or not
 */
bool IsInWindow (uint16_t seq, uint16_t winstart, uint16_t winsize);
/**
 * Add FCS trailer to a packet.
 *
 * \param packet
 */
void AddWifiMacTrailer (Ptr<Packet> packet);
/**
 * Return the total size of the packet after WifiMacHeader and FCS trailer
 * have been added.
 *
 * \param packet the packet to be encapsulated with WifiMacHeader and FCS trailer
 * \param hdr the WifiMacHeader
 * \param isAmpdu whether packet is part of an A-MPDU
 * \return the total packet size
 */
uint32_t GetSize (Ptr<const Packet> packet, const WifiMacHeader *hdr, bool isAmpdu);
/**
 * \param packet the packet to check
 * \returns true if packet is an A-MPDU
 *
 * This method checks if the packet is an A-MPDU by looking for A-MPDU subframe headers.
 */
bool IsAmpdu (Ptr<const Packet> packet);

  /**
   * Get the maximum PPDU duration (see Section 10.14 of 802.11-2016) for
   * the PHY layers defining the aPPDUMaxTime characteristic (HT, VHT and HE).
   * Return zero otherwise.
   *
   * \param preamble the preamble type
   *
   * \return the maximum PPDU duration, if defined, and zero otherwise
   */
  Time GetPpduMaxTime (WifiPreamble preamble);

  /// Size of the space of sequence numbers
  const uint16_t SEQNO_SPACE_SIZE = 4096;

  /// Size of the half the space of sequence numbers (used to determine old packets)
  const uint16_t SEQNO_SPACE_HALF_SIZE = SEQNO_SPACE_SIZE / 2;
} // namespace ns3

#endif /* WIFI_UTILS_H */
